package in.lib.manager; import in.lib.Debug; import in.lib.writer.CacheWriter; import in.lib.writer.CacheWriter.WriterListener; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.security.MessageDigest; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import lombok.Getter; import lombok.Setter; import android.util.Base64; import com.esotericsoftware.kryo.Kryo; import com.esotericsoftware.kryo.io.Input; import com.esotericsoftware.kryo.io.Output; public class CacheManager { @Getter @Setter private String cachePath; private static CacheManager instance; private static final String CACHE_PREFIX = "cache_"; private long lastCheckTime = System.currentTimeMillis(); /** * Gets the cache manager instance or creates it if it's null * @return */ public static CacheManager getInstance() { if (instance == null) { instance = new CacheManager(); } return instance; } public CacheManager() { } private Object lock = new Object(); public void checkLimit() { synchronized (lock) { if (System.currentTimeMillis() - lastCheckTime > 5000) { lastCheckTime = System.currentTimeMillis(); long currentCount = 0L; long limitBytes = SettingsManager.getMaxCacheSize() * 1024 * 1024; List<File> files = Collections.synchronizedList(Arrays.asList(new File(cachePath).listFiles())); synchronized (files) { final Map<File, Long> fileList = new HashMap<File, Long>(); for (final File f : files) { fileList.put(f, f.lastModified()); } Collections.sort(files, new Comparator<File>() { @Override public int compare(final File f1, final File f2) { if (fileList.get(f1) < fileList.get(f2)) { return +1; } else if (fileList.get(f1) > fileList.get(f2)) { return -1; } else { return 0; } } }); for (File f : files) { currentCount += f.length(); if (currentCount > limitBytes) { f.delete(); } } } } } } public boolean fileExists(String file) { if (file.startsWith("/")) { return new File(file).exists(); } return new File(cachePath + "/" + CACHE_PREFIX + file).exists(); } /** * Gets the modified date of the file * @param fileName The file * @return The modified date in ms since 1970 (EPOCH) */ public long fileModifiedDate(String fileName) { File f; if (fileName.startsWith("/")) { f = new File(fileName); } else { f = new File(cachePath + "/" + CACHE_PREFIX + fileName); } return f.lastModified(); } /** * Checks if a file was created before a certain date * @param fileName The file to check * @param date The date to check against * @return True if the file is older, false if not */ public boolean fileOlderThan(String fileName, long date) { long lastDate = fileModifiedDate(fileName); if (lastDate > date) { return false; } return true; } public boolean removeFile(String file) { if (file.startsWith("/")) { return new File(file).delete(); } return new File(cachePath + "/" + CACHE_PREFIX + file).delete(); } public <T> T readFileAsObject(String file, Class<T> out) { try { File f; if (file.startsWith("/")) { f = new File(file); } else { f = new File(cachePath + "/" + CACHE_PREFIX + file); } Kryo kryo = new Kryo(); kryo.setReferences(false); InputStream fis = new BufferedInputStream(new FileInputStream(f), 8196); Input input = new Input(fis, Math.max(1024 * 8, fis.available())); T obj = kryo.readObject(input, out); input.close(); fis.close(); kryo = null; return obj; } catch (Exception e) { Debug.out(e); } return null; } public <T> T readFileAsObject(String file, T def) { Object obj = readFileAsObject(file, def.getClass()); return (T)(obj == null ? def : obj); } public byte[] serialize(Object contents) { if (contents == null) return null; ByteArrayOutputStream bos = new ByteArrayOutputStream(1024 * 8); try { Kryo kryo = new Kryo(); kryo.setReferences(false); Output output = new Output(bos); kryo.writeObject(output, contents); output.close(); kryo = null; return bos.toByteArray(); } catch (Exception e) { Debug.out(e); } finally { try { bos.close(); } catch (Exception e) { Debug.out(e); } } return null; } public <T> T deserialize(byte[] contents, Class<T> outClass) { if (contents == null) return null; Kryo kryo = new Kryo(); kryo.setReferences(false); Input input = new Input(contents); T obj = kryo.readObject(input, outClass); input.close(); kryo = null; return obj; } public void writeFile(String fileName, Object contents) { try { File f; if (fileName.startsWith("/")) { f = new File(fileName); } else { f = new File(cachePath + "/" + CACHE_PREFIX + fileName); } Kryo kryo = new Kryo(); kryo.setReferences(false); OutputStream fos = new BufferedOutputStream(new FileOutputStream(f), 8196); Output output = new Output(fos); kryo.writeObject(output, contents); output.close(); fos.close(); kryo = null; // not sure how badly this may affect performance checkLimit(); } catch (Exception e) { Debug.out(e); } } public void asyncWriteFile(String filename, Object contents) { CacheWriter writer = new CacheWriter(filename); writer.write(contents); } public void asyncWriteFile(String filename, Object contents, WriterListener listener) { CacheWriter writer = new CacheWriter(filename); writer.setWriterListener(listener); writer.write(contents); } /** * Gets a base64'd MD5 hash of an input string * * @param input * The input string * @return The base64 MD5 hash of the input string */ public static String getHash(String input) { String hashFileName = ""; try { MessageDigest md5 = MessageDigest.getInstance("MD5"); hashFileName = Base64.encodeToString(md5.digest(input.getBytes()), Base64.DEFAULT).replace('/', '.'); } catch (Exception e) { Debug.out(e); } return hashFileName; } /** * @brief The class that serailizes data */ public static class Serializer { /** * Serializes data into bytes * @param data The data to be serailized * @return The serialized data in a byte array */ public static byte[] serializeObject(Object data) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutput out = new ObjectOutputStream(bos); out.writeObject(data); byte[] yourBytes = bos.toByteArray(); return yourBytes; } catch (Exception e) { Debug.out(e); return null; } } /** * Deserailizes data into an object * @param data The byte array to be deserialized * @return The data as an object */ public static Object desterializeObject(byte[] data) { try { ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(data)); Object objectData = input.readObject(); input.close(); return objectData; } catch (Exception e) { Debug.out(e); return null; } } } }